package com.juyu.miliao.scheduler.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.juyu.miliao.common.util.DateUtil;
import com.juyu.miliao.common.util.ListGroupUtil;
import com.juyu.miliao.scheduler.dao.mysql.UserInfoDao;
import com.juyu.miliao.scheduler.dao.redis.LineTimeRedisDao;
import com.juyu.miliao.scheduler.domin.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

/**
 * 发现列表 缓存
 * 1.4.3废弃 - 1.5.6重写
 */
@Component
public class QualityHostCacheService {
    private final Logger qualityHostCacheLogger = LoggerFactory.getLogger("qualityHostCache");
    @Resource
    private UserInfoDao userInfoDao;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private LineTimeRedisDao lineTimeRedisDao;

    /**
     * 定时更新缓存内容
     */
    @Scheduled(fixedDelay = 1000 * 40, initialDelay = 1000 * 30)
    public void executeSchedulerJob() {
        try {
            //优质
            QualityHostQuartz qualityHost = new QualityHostQuartz();
            qualityHost.call();
            //新人
            NewQualityHostQuartz newQualityHost = new NewQualityHostQuartz();
            newQualityHost.call();
        } catch (Exception e) {
            qualityHostCacheLogger.error("qualityHost error={}", e);
        }
    }
    //优质列表
    private class QualityHostQuartz {
        private void call() {
            qualityHostCacheLogger.info("--发现--优质主播排行榜排序查询开始：");
            //在线
            Set<String> hostLine = stringRedisTemplate.opsForSet().members("hostLineBySex:2");
            List<Long> hostLineList = hostLine.stream().map(Long::parseLong).collect(toList());
            if(hostLineList.size()>100){
                hostLineList = hostLineList.subList(0,100);
            }
            List<User> lineUserList = new ArrayList<>();
            List<User> callUserList = new ArrayList<>();
            if(hostLine.size()>0){
                List<User> hostLineUserList = userInfoDao.getBeautyHostList(hostLineList);
                for(User user : hostLineUserList){
                    getUserIsLine(user);
                }
                lineUserList = hostLineUserList.stream().filter(i->i.getIsLine()==1).collect(toList());
                for(User user : lineUserList){
                    user.setHourIncome(lineTimeRedisDao.getHomeListIncomeByHostUserByUserId(user.getUserId()));
                }
                //在线列表排序完成
                lineUserList = lineUserList.stream().sorted(comparing(User::getHourIncome).reversed()
                        .thenComparing(comparing(User::getIntegralSum).reversed())).collect(toList());
                //繁忙排序完成
                callUserList = hostLineUserList.stream()
                        .filter(i->i.getIsLine()==2 || i.getIsLine()==3)
                        .sorted(comparing(User::getIntegralSum).reversed())
                        .collect(toList());
            }
            //离线
            int findNum = 100 - hostLineList.size();
            List<User> singOutUserList = new ArrayList<>();
            if(findNum >0){
                LinkedHashMap<Long,Double> map = getLinkedMap("hostUserSingOutDateTime:ByHost",0,findNum);
                for(long key:map.keySet()){
                    Double value = map.get(key);
                    User user = userInfoDao.getUserInfoByUserId(key);
                    user.setSingOutDateTime(value);
                    user.setSingOutDateTimeStr(DateUtil.getSingOutDateTime(value.longValue()));
                    singOutUserList.add(user);
                }
            }
            singOutUserList = singOutUserList.stream().sorted(comparing(User::getSingOutDateTime).reversed()
                                    .thenComparing(comparing(User::getEnergySum).reversed())).collect(toList());
            List<User> userList = new ArrayList<>();
            userList.addAll(lineUserList);
            userList.addAll(callUserList);
            userList.addAll(singOutUserList);

            //置顶
            List<User> top2UserIdList = userInfoDao.getHostLocationConfigByType(1,1);
            List<User> top3UserIdList = userInfoDao.getHostLocationConfigByType(1,2);
            List<User> top6UserIdList = userInfoDao.getHostLocationConfigByType(1,3);
            if(top2UserIdList.size()>0){
                long top2UserId = getTopUserId(top2UserIdList);
                userList = listRemoveObject(userList,top2UserId);
                User user = userInfoDao.getUserInfoByUserId(top2UserId);
                userList.add(1,user);
            }
            if(top3UserIdList.size()>0){
                long top3UserId = getTopUserId(top3UserIdList);
                userList = listRemoveObject(userList,top3UserId);
                User user = userInfoDao.getUserInfoByUserId(top3UserId);
                userList.add(2,user);
            }
            if(top6UserIdList.size()>0){
                long top6UserId = getTopUserId(top6UserIdList);
                userList = listRemoveObject(userList,top6UserId);
                User user = userInfoDao.getUserInfoByUserId(top6UserId);
                userList.add(5,user);
            }
            if(userList.size()>0){
                ObjectMapper mapper = new ObjectMapper();
                List<String> returnList = new ArrayList<>(userList.size());
                userList.forEach(i->{
                    try {
                        returnList.add(mapper.writeValueAsString(i));
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                });
                stringRedisTemplate.delete("qualityHost:all");
                stringRedisTemplate.opsForList().rightPushAll("qualityHost:all",returnList);
            }
            qualityHostCacheLogger.info("--发现--优质主播排行榜排序查询结束：");
        }
    }
    //最新列表
    private class NewQualityHostQuartz {
        private void call() {
            qualityHostCacheLogger.info("--发现--*最新主播排行榜排序查询开始：");
            //在线
            Set<String> hostLine = stringRedisTemplate.opsForSet().members("onLineThreeDaysNewHost");

            qualityHostCacheLogger.info("hostLine.size()::::::"+hostLine.size());
            for(String str:hostLine){
                qualityHostCacheLogger.info("hostLine::::::"+str);
            }
            List<Long> hostLineList = hostLine.stream().map(Long::parseLong).collect(toList());
            if(hostLineList.size()>100){
                hostLineList = hostLineList.subList(0,100);
            }
            List<User> lineUserList = new ArrayList<>();
            List<User> callUserList = new ArrayList<>();
            if(hostLineList.size()>0){
                List<User> hostLineUserList = userInfoDao.getBeautyHostList(hostLineList);
                for(User user:hostLineUserList){
                    qualityHostCacheLogger.info("hostLineUserList::::::"+user.toString());
                }
                for(User user : hostLineUserList){
                    getUserIsLine(user);
                }
                lineUserList = hostLineUserList.stream().filter(i->i.getIsLine()==1).collect(toList());
                for(User user : lineUserList){
                    user.setHourIncome(lineTimeRedisDao.getHomeListIncomeByHostUserByUserId(user.getUserId()));
                }
                //在线列表排序完成
                lineUserList = lineUserList.stream().sorted(comparing(User::getHourIncome).reversed()
                        .thenComparing(comparing(User::getIntegralSum).reversed())).collect(toList());
                for(User user:lineUserList){
                    qualityHostCacheLogger.info("lineUserList::::::"+user.toString());
                }
                //繁忙排序完成
                callUserList = hostLineUserList.stream()
                        .filter(i->i.getIsLine() == 2 || i.getIsLine() == 3)
                        .sorted(comparing(User::getIntegralSum).reversed())
                        .collect(toList());
                for(User user:callUserList){
                    qualityHostCacheLogger.info("callUserList::::::"+user.toString());
                }
            }
            //离线
            int findNum = 100 - hostLineList.size();
            List<User> singOutUserList = new ArrayList<>();
            if(findNum >0){
                LinkedHashMap<Long,Double> map = getLinkedMap("hostUserSingOutDateTime:ByNew",0,findNum);
                for(long key:map.keySet()){
                    Double value = map.get(key);
                    User user = userInfoDao.getUserInfoByUserId(key);
                    user.setSingOutDateTime(value);
                    user.setSingOutDateTimeStr(DateUtil.getSingOutDateTime(value.longValue()));
                    singOutUserList.add(user);
                }
            }
            singOutUserList = singOutUserList.stream().sorted(comparing(User::getSingOutDateTime).reversed()
                    .thenComparing(comparing(User::getEnergySum).reversed())).collect(toList());
            for(User user:singOutUserList){
                qualityHostCacheLogger.info("singOutUserList::::::"+user.toString());
            }
            List<User> userList = new ArrayList<>();
            userList.addAll(lineUserList);
            userList.addAll(callUserList);
            userList.addAll(singOutUserList);

            //置顶
            List<User> top2UserIdList = userInfoDao.getHostLocationConfigByType(2,1);
            List<User> top3UserIdList = userInfoDao.getHostLocationConfigByType(2,2);
            List<User> top6UserIdList = userInfoDao.getHostLocationConfigByType(2,3);
            if(top2UserIdList.size()>0){
                long top2UserId = getTopUserId(top2UserIdList);
                userList = listRemoveObject(userList,top2UserId);
                User user = userInfoDao.getUserInfoByUserId(top2UserId);
                userList.add(1,user);
            }
            if(top3UserIdList.size()>0){
                long top3UserId = getTopUserId(top3UserIdList);
                userList = listRemoveObject(userList,top3UserId);
                User user = userInfoDao.getUserInfoByUserId(top3UserId);
                userList.add(2,user);
            }
            if(top6UserIdList.size()>0){
                long top6UserId = getTopUserId(top6UserIdList);
                userList = listRemoveObject(userList,top6UserId);
                User user = userInfoDao.getUserInfoByUserId(top6UserId);
                userList.add(5,user);
            }
            if(userList.size()>0){
                ObjectMapper mapper = new ObjectMapper();
                List<String> returnList = new ArrayList<>(userList.size());
                userList.forEach(i->{
                    try {
                        returnList.add(mapper.writeValueAsString(i));
                    } catch (JsonProcessingException e) {
                        qualityHostCacheLogger.error(e.getMessage());
                    }
                });
                for(String str:returnList){
                    qualityHostCacheLogger.info("returnList::::::"+str);
                }
                stringRedisTemplate.delete("newQualityHost:all");
                stringRedisTemplate.opsForList().rightPushAll("newQualityHost:all",returnList);
            }
            qualityHostCacheLogger.info("--发现--*最新排行榜排序查询结束：");
        }
    }

    private long getTopUserId(List<User> topList){
        for(User user:topList){
            if (lineTimeRedisDao.isMember(user.getUserId() + "")){
                user.setIsLine(1);
            }
            Boolean isCall = stringRedisTemplate.opsForSet().isMember("hostCall", user.getUserId()+"");
            if (isCall!=null && isCall)
                user.setIsLine(2);
        }
        List<User> lineTopUserList = topList.stream().filter(i->i.getIsLine()==1).collect(toList());
        long userId = 0;
        if(lineTopUserList.size()>0){
            userId = ListGroupUtil.randomListToObject(lineTopUserList).getUserId();
        }else{
            lineTopUserList = topList.stream().filter(i->i.getIsLine()==2).collect(toList());
            if(lineTopUserList.size() > 0){
                userId = ListGroupUtil.randomListToObject(lineTopUserList).getUserId();
            }else{
                userId = ListGroupUtil.randomListToObject(topList).getUserId();
            }
        }
        return userId;
    }

    private List<User> listRemoveObject(List<User> userList ,long userId){
        return userList.stream().filter(i->i.getUserId()!=userId).collect(toList());
    }

    private void getUserIsLine(User user){
        if(user.getIsHost()==1){
            //主播状态设置 0离线，1在线，2繁忙，3勿扰
            // 判断主播是否在线
            if (lineTimeRedisDao.isMember(user.getUserId() + ""))
                user.setIsLine(1);
            //如果用户为主播且正在通话中，则为繁忙状态
            Boolean isCall = stringRedisTemplate.opsForSet().isMember("hostCall", user.getUserId()+"");
            if (user.getIsHost() == 1 && isCall!=null && isCall)
                user.setIsLine(2);
            // 判断用户是否勿扰
            if (user.getIsVideo() == 2)
                user.setIsLine(3);
        }else {
            // 判断用户是否在线
            if (lineTimeRedisDao.hasKeyLine(user.getUserId() + ""))
                user.setIsLine(1);
            // 判断用户是否勿扰
            if (user.getIsVideo() == 2)
                user.setIsLine(3);
        }
    }

    /**
     * 根据分值倒序，获取ZSet--value|score
     * @param zset key
     * @return map<value,score>
     */
    private LinkedHashMap<Long,Double> getLinkedMap(String key,int start ,int end){
        Set<ZSetOperations.TypedTuple<String>> reverseRangeWithScores = stringRedisTemplate.opsForZSet().
                reverseRangeWithScores(key, start, end);
        Iterator<ZSetOperations.TypedTuple<String>> iterator = reverseRangeWithScores.iterator();
        LinkedHashMap<Long,Double> map = new LinkedHashMap<>(reverseRangeWithScores.size());
        while(iterator.hasNext()){
            ZSetOperations.TypedTuple<String> next = iterator.next();
            map.put(Long.parseLong(next.getValue()),next.getScore());
        }
        return map;
    }

}
